package xyz.molzhao.cfapi;

import xyz.molzhao.util.CommonUtil;

import java.util.concurrent.CompletableFuture;

/**
 * 场景：
 * 小明买单，把钱付给服务员并要求开发票，服务员收到款之后就去开发票，同时小明也没有闲着
 * 接了个电话准备回去开黑，刚接完电话服务员就过来，于是小明就走出餐厅，准备回家。
 */
public class Apply {

    /**
     * 小明和服务员分别在不同的两个线程
     */
    public static void method1() {
        CommonUtil.createBehavior("小明吃好了");
        CommonUtil.createBehavior("小明 结账、要求发票");

        CompletableFuture<String> invoice = CompletableFuture.supplyAsync(() -> {
            CommonUtil.createBehavior("服务员收款 500元", 100);
            CommonUtil.createBehavior("服务员开发票 面额 500元", 1000);
            return "500元发票";
        });
        CommonUtil.createBehavior("小明接到朋友电话，想一起打游戏");
        CommonUtil.createBehavior(String.format("小明拿到%s,准备回家", invoice.join()));
    }

    /**
     * 如果要求收款和开发票的两个服务员不在同一个线程，我们如何实现
     */
    public static void method2() {
        CommonUtil.createBehavior("小明吃好了");
        CommonUtil.createBehavior("小明 结账、要求发票");

        CompletableFuture<String> invoice = CompletableFuture.supplyAsync(() -> {
            CommonUtil.createBehavior("服务员收款 500元", 100);


            CompletableFuture<String> waiter2 = CompletableFuture.supplyAsync(() -> {
                CommonUtil.createBehavior("服务员开发票 面额 500元", 1000);
                return "500元发票";
            });

            return waiter2.join();
        });

        CommonUtil.createBehavior("小明接到朋友电话，想一起打游戏");
        CommonUtil.createBehavior(String.format("小明拿到%s,准备回家", invoice.join()));
    }

    /**
     * 上面两种方法两个操作都放在同一代码块中，两个服务员也都放在同一代码块中，如果我们
     * 要修改其中一段逻辑就会影响另一段逻辑这是十分不好的。
     */
    public static void method3() {
        CommonUtil.createBehavior("小明吃好了");
        CommonUtil.createBehavior("小明 结账、要求发票");

        CompletableFuture<String> invoice = CompletableFuture.supplyAsync(() -> {
            CommonUtil.createBehavior("服务员收款 500元", 100);
            return "500";
        }).thenApply(money -> {
            CommonUtil.createBehavior(String.format("服务员开发票 面额 %s", money), 1000);
            return String.format("%s元发票", money);
        });

        CommonUtil.createBehavior("小明接到朋友电话，想一起打游戏");
        CommonUtil.createBehavior(String.format("小明拿到%s,准备回家", invoice.join()));
    }

    /**
     * 我们发现上面这种写法开发票和收款是同一个服务员，也就是在同一个线程，如果我们要两个服务员操作,我们怎么办
     *
     * 这里两个线程我这边展示出来是一个线程，是因为线程间调度判断上个线程已经空闲了就直接复用了
     */
    public static void method4() {
        CommonUtil.createBehavior("小明吃好了");
        CommonUtil.createBehavior("小明 结账、要求发票");

        CompletableFuture<String> invoice = CompletableFuture.supplyAsync(() -> {
            CommonUtil.createBehavior("服务员收款 500元", 2000);
            return "500";
        }).thenApplyAsync(money -> {
            CommonUtil.createBehavior(String.format("服务员开发票 面额 %s", money), 1000);
            return String.format("%s元发票", money);
        });

        CommonUtil.createBehavior("小明接到朋友电话，想一起打游戏");
        CommonUtil.createBehavior(String.format("小明拿到%s,准备回家", invoice.join()));
    }

    public static void main(String[] args) {
//        method1();
//        System.out.println("-----------------------------");
//        method2();
//        System.out.println("-----------------------------");
//        method3();
//        System.out.println("-----------------------------");
        method4();
    }
}
